

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <time.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

struct drm_device {
	uint32_t width;			//显示器的宽的像素点数量
	uint32_t height;		//显示器的高的像素点数量
	uint32_t pitch;			//每行占据的字节数
	uint32_t handle;		//drm_mode_create_dumb的返回句柄
	uint32_t size;			//显示器占据的总字节数
	uint32_t *vaddr;		//mmap的首地址
	uint32_t fb_id;			//创建的framebuffer的id号
	struct drm_mode_create_dumb create ;	//创建的dumb
 	struct drm_mode_map_dumb map;			//内存映射结构体
};

struct property_crtc {
	uint32_t blob_id;
	uint32_t property_crtc_id;
	uint32_t property_mode_id;
	uint32_t property_active;
	
	uint32_t property_rotation_id;
};

drmModeConnector *conn;	    //connetor相关的结构体
drmModeConnector *conn2;	//connetor相关的结构体
drmModeRes *res;		//资源
drmModePlaneRes *plane_res;

int fd;					//文件描述符
uint32_t conn_id;
uint32_t crtc_id;

uint32_t conn_id2;
uint32_t crtc_id2;

uint32_t plane_id[24];

#define RED 0XFF0000
#define GREEN 0X00FF00
#define BLUE 0X0000FF


uint32_t color_table[6] = {RED,GREEN,BLUE,RED,GREEN,BLUE};
uint32_t color_table2[6] = {GREEN,BLUE,RED,RED,GREEN,BLUE};

struct drm_device buf;
struct drm_device buf2;
struct property_crtc pc;

static int drm_create_fb(struct drm_device *bo)
{
	/* create a dumb-buffer, the pixel format is XRGB888 */
	bo->create.width  = bo->width;
	bo->create.height = bo->height;
	bo->create.bpp = 32;

	/* handle, pitch, size will be returned */
	drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &bo->create);

	/* bind the dumb-buffer to an FB object */
	bo->pitch = bo->create.pitch;
	bo->size = bo->create.size;
	bo->handle = bo->create.handle;
	drmModeAddFB(fd, bo->width, bo->height, 24, 32, bo->pitch,bo->handle, &bo->fb_id);
	
	//每行占用字节数，共占用字节数，MAP_DUMB的句柄
	printf("pitch = %d ,size = %d, handle = %d \n",bo->pitch,bo->size,bo->handle);

	/* map the dumb-buffer to userspace */
	bo->map.handle = bo->create.handle;
	drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &bo->map);

	bo->vaddr = mmap(0, bo->create.size, PROT_READ | PROT_WRITE,MAP_SHARED, fd, bo->map.offset);

	/* initialize the dumb-buffer with white-color */
	memset(bo->vaddr, 0xff,bo->size);

	return 0;
}

static void drm_destroy_fb(struct drm_device *bo)
{
	struct drm_mode_destroy_dumb destroy = {};
	drmModeRmFB(fd, bo->fb_id);
	munmap(bo->vaddr, bo->size);
	destroy.handle = bo->handle;
	drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy);
}

static uint32_t get_property(int fd, drmModeObjectProperties *props)
{
	drmModePropertyPtr property;
	uint32_t i, id = 0;

	for (i = 0; i < props->count_props; i++) {
		property = drmModeGetProperty(fd, props->props[i]);
		printf("\"%s\"\t\t---",property->name);
		printf("id = %d , value=%ld\n",props->props[i],props->prop_values[i]);
	}
    return 0;
}

static uint32_t get_property_id(int fd, drmModeObjectProperties *props,
				const char *name)
{
	drmModePropertyPtr property;
	uint32_t i, id = 0;


	/* find property according to the name */
	for (i = 0; i < props->count_props; i++) {
		property = drmModeGetProperty(fd, props->props[i]);
		if (!strcmp(property->name, name))
			id = property->prop_id;
		drmModeFreeProperty(property);

		if (id)
			break;
	}

	return id;
}

int drm_init()
{
	int i;
	int ret = 0;

	drmModeObjectProperties *props;
	drmModeAtomicReq *req;

	fd  = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
	if(fd <= 0){
		return -1;
	}
	res = drmModeGetResources(fd);
	if(!res){
		printf("-----get res error----\n");	
		close(fd);
		fd = 0;
		return -1;
	}

	printf("count_fbs       =%d\n",res->count_fbs);
	printf("count_crtcs     =%d\n",res->count_crtcs);
	printf("count_connectors=%d\n",res->count_connectors);
	printf("count_encoders  =%d\n",res->count_encoders);

	printf("min_width   =%d\n",res->min_width);
	printf("max_width   =%d\n",res->max_width);
	
	printf("min_height  =%d\n",res->min_height);
	printf("max_height  =%d\n",res->max_height);

#if 0
	typedef struct _drmModeRes {
	
		int count_fbs;
		uint32_t *fbs;
	
		int count_crtcs;
		uint32_t *crtcs;
	
		int count_connectors;
		uint32_t *connectors;
	
		int count_encoders;
		uint32_t *encoders;
	
		uint32_t min_width, max_width;
		uint32_t min_height, max_height;
	} drmModeRes, *drmModeResPtr;
#endif


	crtc_id = res->crtcs[0];
	conn_id = res->connectors[0];

	crtc_id2 = res->crtcs[1];
	conn_id2 = res->connectors[1];

	ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
	if(ret < 0){
		printf("set client cap error.\n");
		close(fd);
		fd = 0;
		return -1;
	}

	plane_res = drmModeGetPlaneResources(fd);
	#if 0
	typedef struct _drmModePlaneRes {
		uint32_t count_planes;
		uint32_t *planes;
	} drmModePlaneRes, *drmModePlaneResPtr;
	#endif

	printf("count_planes  =%d\n",plane_res->count_planes);

	for(i=0;i<plane_res->count_planes;i++)
	{
		plane_id[i] = plane_res->planes[i];
		printf("planes[%d]= %d\n",i,plane_id[i]);
	}
	
	conn = drmModeGetConnector(fd, conn_id);
	conn2 = drmModeGetConnector(fd, conn_id2);



#if 0
	typedef struct _drmModeConnector {
		uint32_t connector_id;
		uint32_t encoder_id; /**< Encoder currently connected to */
		uint32_t connector_type;
		uint32_t connector_type_id;
		drmModeConnection connection;
		uint32_t mmWidth, mmHeight; /**< HxW in millimeters */
		drmModeSubPixel subpixel;
	
		int count_modes;
		drmModeModeInfoPtr modes;
	
		int count_props;
		uint32_t *props; /**< List of property ids */
		uint64_t *prop_values; /**< List of property values */
	
		int count_encoders;
		uint32_t *encoders; /**< List of encoder ids */
	} drmModeConnector, *drmModeConnectorPtr;


	typedef struct _drmModeModeInfo {
		uint32_t clock;
		uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
		uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
	
		uint32_t vrefresh;
	
		uint32_t flags;
		uint32_t type;
		char name[DRM_DISPLAY_MODE_LEN];
	} drmModeModeInfo, *drmModeModeInfoPtr;

#endif

	
	printf("connector_id     =%d\n",conn->connector_id);
	printf("encoder_id       =%d\n",conn->encoder_id);
	printf("connector_type   =%d\n",conn->connector_type);
	printf("connector_type_id=%d\n",conn->connector_type_id);
	printf("mmWidth  		 =%d\n",conn->mmWidth);
	printf("mmHeight         =%d\n",conn->mmHeight);
	printf("count_modes      =%d\n",conn->count_modes);
	printf("count_props      =%d\n",conn->count_props);
	printf("count_encoders   =%d\n",conn->count_encoders);

	printf("hdisplay   =%d\n",conn->modes[0].hdisplay);
	printf("vdisplay   =%d\n",conn->modes[0].vdisplay);
	printf("clock      =%d\n",conn->modes[0].clock);
	printf("vrefresh   =%d\n",conn->modes[0].vrefresh);
	printf("name       =%s\n",conn->modes[0].name);

	printf("hdisplay   =%d\n",conn->modes[1].hdisplay);
	printf("vdisplay   =%d\n",conn->modes[1].vdisplay);
	printf("clock      =%d\n",conn->modes[1].clock);
	printf("vrefresh   =%d\n",conn->modes[1].vrefresh);
	printf("name       =%s\n",conn->modes[1].name);
	
	printf("connector_id     =%d\n",conn2->connector_id);
	printf("encoder_id       =%d\n",conn2->encoder_id);
	printf("connector_type   =%d\n",conn2->connector_type);
	printf("connector_type_id=%d\n",conn2->connector_type_id);
	printf("mmWidth  		 =%d\n",conn2->mmWidth);
	printf("mmHeight         =%d\n",conn2->mmHeight);
	printf("count_modes      =%d\n",conn2->count_modes);
	printf("count_props      =%d\n",conn2->count_props);
	printf("count_encoders   =%d\n",conn2->count_encoders);

	

	printf("hdisplay   =%d\n",conn2->modes[0].hdisplay);
	printf("vdisplay   =%d\n",conn2->modes[0].vdisplay);
	printf("clock      =%d\n",conn2->modes[0].clock);
	printf("vrefresh   =%d\n",conn2->modes[0].vrefresh);
	printf("name       =%s\n",conn2->modes[0].name);

	printf("hdisplay   =%d\n",conn2->modes[1].hdisplay);
	printf("vdisplay   =%d\n",conn2->modes[1].vdisplay);
	printf("clock      =%d\n",conn2->modes[1].clock);
	printf("vrefresh   =%d\n",conn2->modes[1].vrefresh);
	printf("name       =%s\n",conn2->modes[1].name);


	buf.width   = conn->modes[0].hdisplay;
	buf.height  = conn->modes[0].vdisplay;
	
	buf2.width  = conn2->modes[0].hdisplay;
	buf2.height = conn2->modes[0].vdisplay;

	
	drm_create_fb(&buf);
	drm_create_fb(&buf2);

	drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1);
	drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
	

	drmModeCreatePropertyBlob(fd, &conn->modes[4],sizeof(conn->modes[4]), &pc.blob_id);

	//********************************************************************************
	printf("**************************************************************************\n");
	printf("DRM_MODE_OBJECT_CONNECTOR\n");
	props = drmModeObjectGetProperties(fd, conn_id,	DRM_MODE_OBJECT_CONNECTOR);
	get_property(fd, props);
	uint32_t brightness = get_property_id(fd, props, "brightness");
	uint32_t contrast   = get_property_id(fd, props, "contrast");
	uint32_t saturation = get_property_id(fd, props, "saturation");
	uint32_t hue        = get_property_id(fd, props, "hue");

	req = drmModeAtomicAlloc();
	drmModeAtomicAddProperty(req, conn_id, brightness, 50);
	drmModeAtomicAddProperty(req, conn_id, contrast, 50);	
	drmModeAtomicAddProperty(req, conn_id, saturation, 50);
	drmModeAtomicAddProperty(req, conn_id, hue, 50);
	drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
	drmModeAtomicFree(req);
	
	printf("*******************************\n");
	get_property(fd, props);
	drmModeFreeObjectProperties(props);
	printf("**************************************************************************\n");
	printf("DRM_MODE_OBJECT_CRTC\n");

	props = drmModeObjectGetProperties(fd, crtc_id, DRM_MODE_OBJECT_CRTC);
	get_property(fd, props);
	drmModeFreeObjectProperties(props);
	printf("**************************************************************************\n");
	printf("DRM_MODE_OBJECT_PLANE\n");

	for(i=0;i<plane_res->count_planes;i++)
	{
		props = drmModeObjectGetProperties(fd,plane_id[i], DRM_MODE_OBJECT_PLANE );
		get_property(fd, props);
		uint32_t color_space = get_property_id(fd, props, "COLOR_SPACE");
		uint32_t rotation    = get_property_id(fd, props, "rotation");
		uint32_t SHARE_ID    = get_property_id(fd, props, "SHARE_ID");
		uint32_t colorkey    = get_property_id(fd, props, "colorkey");
		uint32_t CRTC_ID     = get_property_id(fd, props, "CRTC_ID");

		//printf("color_space=%d\n",color_space);
		//printf("rotation   =%d\n",rotation);
		//printf("SHARE_ID   =%d\n",SHARE_ID);
		//printf("colorkey   =%d\n",colorkey);

		//printf("plane_id[%d]   =%d\n",i,plane_id[i]);

		req = drmModeAtomicAlloc();
		
		#if 0
		drmModeAtomicAddProperty(req, crtc_id, color_space, 6);
		drmModeAtomicAddProperty(req, crtc_id, rotation, 2);
		drmModeAtomicAddProperty(req, crtc_id, SHARE_ID, 2);
		#endif

		#if 0
		drmModeAtomicAddProperty(req, conn_id, color_space, 6);
		drmModeAtomicAddProperty(req, conn_id, rotation, 2);
		drmModeAtomicAddProperty(req, conn_id, SHARE_ID, 2);
		#endif
		
		#if 1
		//drmModeAtomicAddProperty(req, plane_id[i], CRTC_ID,crtc_id);
		//drmModeAtomicAddProperty(req, plane_id[i], color_space, 6);
		drmModeAtomicAddProperty(req, plane_id[i], rotation, 2);
		//drmModeAtomicAddProperty(req, plane_id[i], SHARE_ID, 2);
		//drmModeAtomicAddProperty(req, plane_id[i], colorkey, 2);
		#endif

		//drmModeObjectSetProperty(fd, plane_id[i], DRM_MODE_OBJECT_PLANE, color_space, 6);
		drmModeObjectSetProperty(fd, plane_id[i], DRM_MODE_OBJECT_PROPERTY, rotation, 2);

		ret = drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
		printf("commit_ret=%d\n",ret);
		if(!ret){
			printf("plane_id[%d]	 =%d\n",i,plane_id[i]);
		}
		drmModeAtomicFree(req);

		drmModeFreeObjectProperties(props);
	
	}


	/*
	struct property_arg prop_rotation_args;
	
	prop_rotation_args.obj_id	= 122;//54 74 108 122 136
	prop_rotation_args.obj_type = DRM_MODE_OBJECT_PLANE;
	sprintf(prop_rotation_args.name,"%s","rotation");
	prop_rotation_args.prop_id	= 124;
	prop_rotation_args.value	= 0x2;
	
	set_property(&dev, &prop_rotation_args);	
	*/

	printf("**************************************************************************\n");
	printf("DRM_MODE_OBJECT_BLOB\n");


	//props = drmModeObjectGetProperties(fd,pc.blob_id, DRM_MODE_OBJECT_PROPERTY );
	//get_property(fd, props);
	//pc.blob_id = get_property_id(fd, props, "rotation");
	//printf("property_rotation_id=%d\n",pc.property_rotation_id);
	//drmModeFreeObjectProperties(props);
	printf("**************************************************************************\n");

	
	//printf("DRM_MODE_OBJECT_PROPERTY\n");

	//props = drmModeObjectGetProperties(fd, plane_id[0], DRM_MODE_OBJECT_PROPERTY);
	//get_property(fd, props);
	//drmModeFreeObjectProperties(props);
	printf("end\n");
	printf("**************************************************************************\n");
	//********************************************************************************

	//drmModeObjectSetProperty(fd,  plane_id[1], DRM_MODE_OBJECT_PLANE, pc.property_rotation_id, 2);

	/* start modeseting */


	//********************************************************************************
	printf("**************************************************************************\n");
	printf("SECOND CHECK DRM_MODE_OBJECT_PLANE\n");

	props = drmModeObjectGetProperties(fd,plane_id[0], DRM_MODE_OBJECT_PLANE );
	get_property(fd, props);
	drmModeFreeObjectProperties(props);	
	printf("**************************************************************************\n");
	//********************************************************************************

	#if 0
	props = drmModeObjectGetProperties(fd, conn_id2,	DRM_MODE_OBJECT_CONNECTOR);
	get_property(fd, props);
	pc.property_crtc_id = get_property_id(fd, props, "CRTC_ID");
	drmModeFreeObjectProperties(props);
	//********************************************************************************

	/* get crtc properties */
	props = drmModeObjectGetProperties(fd, crtc_id2, DRM_MODE_OBJECT_CRTC);
	get_property(fd, props);
	pc.property_active = get_property_id(fd, props, "ACTIVE");
	printf("property_active=%d\n",pc.property_active);

	pc.property_mode_id = get_property_id(fd, props, "MODE_ID");
	printf("property_mode_id=%d\n",pc.property_mode_id);


	drmModeFreeObjectProperties(props);
	//********************************************************************************
	//get plane 
	
	props = drmModeObjectGetProperties(fd, plane_id[0], DRM_MODE_OBJECT_PROPERTY);
	get_property(fd, props);
	
	pc.property_rotation_id = get_property_id(fd, props, "rotation");
	printf("property_rotation_id=%d\n",pc.property_rotation_id);

	drmModeFreeObjectProperties(props);
	#endif
	//********************************************************************************
	


	//********************************************************************************

	#if 0
	printf("**************************************************************************\n");

	props = drmModeObjectGetProperties(fd, plane_id[0], DRM_MODE_OBJECT_PROPERTY);
	get_property(fd, props);
	
	pc.property_rotation_id = get_property_id(fd, props, "rotation");
	printf("property_rotation_id=%d\n",pc.property_rotation_id);

	drmModeFreeObjectProperties(props);
	//********************************************************************************
	/* create blob to store current mode, and retun the blob id */
	drmModeCreatePropertyBlob(fd, &conn2->modes[0],
				sizeof(conn2->modes[0]), &pc.blob_id);

	/* start modeseting */
	req = drmModeAtomicAlloc();
	drmModeAtomicAddProperty(req, crtc_id2, pc.property_active, 1);
	drmModeAtomicAddProperty(req, crtc_id2, pc.property_mode_id, pc.blob_id);
	drmModeAtomicAddProperty(req, conn_id2, pc.property_crtc_id, crtc_id2);
	drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
	drmModeAtomicFree(req);
	#endif
	//********************************************************************************

	


	return 0;
}

int drm_exit()
{
	drm_destroy_fb(&buf);
	drm_destroy_fb(&buf2);
	
	drmModeFreeConnector(conn);
	drmModeFreeConnector(conn2);
	drmModeFreePlaneResources(plane_res);
	drmModeFreeResources(res);
	close(fd);
}

int main(int argc, char **argv)
{
	int i,j;
	if(drm_init() < 0){
		
		return -1;
	}
	//显示三色
	for(j=0;j<3;j++){
		for(i =j*buf.width*buf.height/3;i< (j+1)*buf.width*buf.height/3;i++)
			buf.vaddr[i] = color_table[j];
	}

	for(j=0;j<3;j++){
		for(i =j*buf2.width*buf2.height/3;i< (j+1)*buf2.width*buf2.height/3;i++)
			buf2.vaddr[i] = color_table2[j];
	}

	int index  = 0;
	int index2 = 5;
	//************************************************************************
	//1：1设置屏幕，没有该函数不会显示画面
	drmModeSetPlane(fd, plane_id[index], crtc_id, buf.fb_id, 0,
			0, 0, buf.width, buf.height,
			0 << 16, 0 << 16, buf.width << 16, buf.height << 16);

	#if 1
	drmModeSetPlane(fd, plane_id[index2], crtc_id2, buf2.fb_id, 0,
			0, 0, buf2.width, buf2.height,
			0 << 16, 0 << 16, buf2.width << 16, buf2.height << 16);
	#endif
	//************************************************************************


	getchar();
	//将framebuffer上2/3的区域放到图层一上，
	//此时屏幕改变，将的framebuffer区域拉伸到整个屏幕中
	drmModeSetPlane(fd, plane_id[index], crtc_id, buf.fb_id, 0,
			0, 0, buf.width, buf.height,
			0 << 16, 0 << 16, buf.width << 16, buf.height/3*2 << 16);

	#if 1
	drmModeSetPlane(fd, plane_id[index2], crtc_id2, buf2.fb_id, 0,
			0, 0, buf2.width, buf2.height,
			0 << 16, 0 << 16, buf2.width << 16, buf2.height/3*2 << 16);
	#endif
	//************************************************************************

	getchar();
	//将framebuffer区域缩放一倍放到图层二上，把图层二的位置放到屏幕的下方
	//叠加在图层一上，可以看到图层二覆盖了图层一的部分区域
	drmModeSetPlane(fd, plane_id[index], crtc_id, buf.fb_id, 0,
			buf.width/4, buf.height/2, buf.width/2, buf.height/2,
			0 << 16, 0 << 16, buf.width << 16, buf.height << 16);

	#if 1
	drmModeSetPlane(fd, plane_id[index2], crtc_id2, buf2.fb_id, 0,
				buf2.width/4, buf2.height/2, buf2.width/2, buf2.height/2,
				0 << 16, 0 << 16, buf2.width << 16, buf2.height << 16);
	#endif
	//************************************************************************

	getchar();

	drm_exit();	

	return 0;
}



